package com.oem.android.activity.file;

import static com.oem.android.contant.URLConstant.GATEWAY_URL;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.InputType;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Toast;
import android.widget.VideoView;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
import com.oem.android.R;
import com.oem.android.config.RetrofitClient;
import com.oem.android.model.Result;
import com.oem.android.model.file.UploadFileParamsDto;
import com.oem.android.service.FileService;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.HashMap;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class FileChooserActivity extends AppCompatActivity {

    private static final String TAG = "FileChooserActivity";
    private static final int PERMISSION_REQUEST_CODE = 1;
    private static final Gson gson = createGsonInstance();

    // 用于启动intent跳转的启动器
    private final ActivityResultLauncher<Intent> galleryLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                // 检查文件选择操作是否成功并且返回的数据是否不为空
                if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
                    Uri fileUri = result.getData().getData();
                    Log.d(TAG, "选中的文件 URI: " + fileUri);
                    showGalleryUploadDialog(fileUri);
                } else {
                    Toast.makeText(this, "未选择文件", Toast.LENGTH_SHORT).show();
                }
            }
    );

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file_chooser);

        Button btnSelectFromGallery = findViewById(R.id.btn_select_from_gallery);
        Button btnUploadUrl = findViewById(R.id.btn_upload_url);
        Button btnDownloadUrl = findViewById(R.id.btn_download_url);

        // 为三种选择按钮绑定单击事件
        btnSelectFromGallery.setOnClickListener(view -> openGallery());
        btnUploadUrl.setOnClickListener(view -> showUrlUploadDialog());
    }

    // 处理权限请求结果
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE) {
            // 如果权限被拒绝，则输出错误日志信息。
            if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "存储权限被拒绝，无法继续操作", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "权限授予成功！", Toast.LENGTH_SHORT).show();
            }
        }
    }

    // 打开图库
    private void openGallery() {
        // 创建一个用于获取内容的Intent
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        // 设置Intent的类型为任意文件类型
        intent.setType("*/*");
        // 定义一个字符串数组，包含图片和视频的MIME类型
        String[] mimeTypes = {"image/*", "video/*"};
        // 将MIME类型数组作为额外参数添加到Intent中，这样选择器会显示图片和视频文件
        intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
        // 使用之前定义的ActivityResultLauncher启动选择器
        galleryLauncher.launch(intent);
    }

    // 显示图库上传弹框
    private void showGalleryUploadDialog(Uri fileUri) {
        // 创建弹框视图
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View dialogView = inflater.inflate(R.layout.dialog_upload, null);

        ImageView filePreview = dialogView.findViewById(R.id.filePreview);
        VideoView videoPreview = dialogView.findViewById(R.id.videoPreview);
        LinearLayout formContainer = dialogView.findViewById(R.id.formContainer);

        // 获取文件 MIME 类型
        ContentResolver contentResolver = getContentResolver();
        String mimeType = contentResolver.getType(fileUri);
        Log.d(TAG, "文件的mimeType类型就是" + mimeType);

        // 根据 MIME 类型设置预览
        if (mimeType != null) {
            if (mimeType.startsWith("image/")) {
                // 显示图片预览
                filePreview.setVisibility(View.VISIBLE);
                videoPreview.setVisibility(View.GONE); // 隐藏视频预览
                try {
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(contentResolver, fileUri);
                    filePreview.setImageBitmap(bitmap);
                } catch (IOException e) {
                    filePreview.setImageResource(R.drawable.ic_file_preview); // 默认文件预览图标
                }
            } else if (mimeType.startsWith("video/")) {
                // 显示视频预览
                filePreview.setVisibility(View.GONE); // 隐藏图片预览
                videoPreview.setVisibility(View.VISIBLE);
                videoPreview.setVideoURI(fileUri);
                videoPreview.start(); // 自动播放视频
            } else {
                // 不支持的文件类型
                filePreview.setVisibility(View.VISIBLE);
                videoPreview.setVisibility(View.GONE);
                filePreview.setImageResource(R.drawable.ic_file_preview); // 默认文件预览图标
            }
        }

        // 创建输入框
        Map<String, EditText> inputFields = createInputFields();

        // 将输入框添加到布局
        formContainer.addView(inputFields.get("tags"));
        formContainer.addView(inputFields.get("category"));
        formContainer.addView(inputFields.get("budget"));
        formContainer.addView(inputFields.get("startDate"));
        formContainer.addView(inputFields.get("endDate"));
        formContainer.addView(inputFields.get("description"));
        formContainer.addView(inputFields.get("remark"));

        // 设置按钮行为
        builder.setPositiveButton("上传", (dialog, which) -> {
            String budgetStr = inputFields.get("budget").getText().toString().trim().isEmpty() ? "3000.0" : "5000.0";
            String startDateStr = inputFields.get("startDate").getText().toString().trim().isEmpty() ? "2024-12-30T12:12:11" : "2024-12-30T12:12:12";
            String endDateStr = inputFields.get("endDate").getText().toString().trim().isEmpty() ? "2025-01-05T23:59:58" : "2025-01-05T23:59:59";

            // TODO 日期应该由用户进行日历选择，而不是手动输入字符串
            // TODO 前后端LocalDateTime的序列化还需要优化和测试
            // 仅便于调试，后期删除

            // 验证其他参数
            Map<String, Object> map = checkAndProcessParams(budgetStr, startDateStr, endDateStr);

            // 创建 DTO
            UploadFileParamsDto uploadFileParams = createUploadParams(inputFields);

            // 获取文件路径
            // TODO getRealPathFromURI 在高版本 Android 中可能会失效
            String filePath = getRealPathFromURI(fileUri);
            Log.d(TAG, "文件路径是" + filePath);

            if (filePath != null) {
                File file = new File(filePath);
                // 调用uploadFile方法将文件上传到服务器
                uploadGalleryFile(file, uploadFileParams);
            } else {
                Toast.makeText(this, "无法获取文件路径", Toast.LENGTH_SHORT).show();
            }
        });

        // 取消按钮逻辑
        builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());
        builder.setView(dialogView);

        // 显示对话框
        AlertDialog dialog = builder.create();
        dialog.setCancelable(false);
        dialog.show();
    }

    private void uploadGalleryFile(File file, UploadFileParamsDto uploadFileParamsDto) {
        // 1.1 构建 Json 参数
        String paramsJson = gson.toJson(uploadFileParamsDto);
        // 1.2 创建 DTO 参数请求体
        RequestBody paramsRequestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), paramsJson);

        // 2.1 获取文件的 mimeType
        String mimeType = getMimeType(file.getAbsolutePath());
        Log.d(TAG, "文件的mimeType为：" + mimeType);
        // 2.2 创建 fileRequestBody
        RequestBody fileRequestBody = RequestBody.create(MediaType.parse(mimeType), file);
        // 2.3 创建 MultipartBody.Part
        MultipartBody.Part filePart = MultipartBody.Part.createFormData("obj", file.getName(), fileRequestBody);

        // 3.1 构建 RetrofitClient
        FileService fileService = RetrofitClient
                .getClient(GATEWAY_URL)
                .create(FileService.class);

        // 3.2 调用上传接口
        fileService.uploadFileByGallery(filePart, paramsRequestBody).enqueue(new Callback<Result>() {
            @Override
            public void onResponse(Call<Result> call, Response<Result> response) {
                handleResponse(FileChooserActivity.this, TAG, response, null);
            }

            @Override
            public void onFailure(Call<Result> call, Throwable t) {
                handleResponse(FileChooserActivity.this, TAG, null, t);
            }
        });
    }

    // 显示 URL 上传弹框
    private void showUrlUploadDialog() {
        // 创建一个ScrollView，允许输入框数量较多时滚动
        ScrollView scrollView = new ScrollView(this);
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);

        // 创建输入框
        Map<String, EditText> inputFields = createInputFields();

        // 将输入框添加到布局
        layout.addView(inputFields.get("url"));
        layout.addView(inputFields.get("tags"));
        layout.addView(inputFields.get("category"));
        layout.addView(inputFields.get("budget"));
        layout.addView(inputFields.get("startDate"));
        layout.addView(inputFields.get("endDate"));
        layout.addView(inputFields.get("description"));
        layout.addView(inputFields.get("remark"));

        // 将布局嵌入到ScrollView
        scrollView.addView(layout);

        // 创建对话框
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("输入广告参数");
        builder.setView(scrollView);

        // 确认按钮逻辑
        builder.setPositiveButton("上传", (dialog, which) -> {
            // 获取用户输入内容
            String url = inputFields.get("url").getText().toString().trim();
            String budgetStr = inputFields.get("budget").getText().toString().trim().isEmpty() ? "3000.0" : "5000.0";
            String startDateStr = inputFields.get("startDate").getText().toString().trim().isEmpty() ? "2024-12-30T12:12:11" : "2024-12-30T12:12:12";
            String endDateStr = inputFields.get("endDate").getText().toString().trim().isEmpty() ? "2025-01-05T23:59:58" : "2025-01-05T23:59:59";

            // 检查URL是否为空
            if (url.isEmpty()) {
                Toast.makeText(this, "URL 不能为空", Toast.LENGTH_SHORT).show();
                return;
            }

            // TODO 日期应该由用户进行日历选择，而不是手动输入字符串
            // TODO 前后端LocalDateTime的序列化还需要优化和测试（统一格式）
            // 仅便于调试，后期删除

            // 验证其他参数
            Map<String, Object> map = checkAndProcessParams(budgetStr, startDateStr, endDateStr);

            // 创建 DTO
            UploadFileParamsDto uploadFileParams = createUploadParams(inputFields);

            // 调用上传方法
            uploadUrlFile(url, uploadFileParams);
        });

        // 取消按钮逻辑
        builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());

        // 显示对话框
        AlertDialog dialog = builder.create();
        dialog.setCancelable(false);
        dialog.show();
    }

    private void uploadUrlFile(String url, UploadFileParamsDto uploadFileParamsDto) {
        // 将对象序列化为 JSON，并自定义序列化器
        String paramsJson = gson.toJson(uploadFileParamsDto);

        // 使用 RetrofitClient 初始化 Retrofit 和 FileService
        FileService fileService = RetrofitClient
                .getClient(GATEWAY_URL) // 替换为你的后端服务器地址
                .create(FileService.class);

        // 创建 RequestBody
        RequestBody urlRequestBody = RequestBody.create(MediaType.parse("text/plain"), url);
        RequestBody paramsRequestBody = RequestBody.create(MediaType.parse("application/json"), paramsJson);

        // 调用上传接口
        fileService.uploadFileByURL(urlRequestBody, paramsRequestBody).enqueue(new Callback<Result>() {
            @Override
            public void onResponse(Call<Result> call, Response<Result> response) {
                handleResponse(FileChooserActivity.this, TAG, response, null);
            }

            @Override
            public void onFailure(Call<Result> call, Throwable t) {
                handleResponse(FileChooserActivity.this, TAG, null, t);
            }
        });
    }

    // 根据URI获取文件的绝对路径
    private String getRealPathFromURI(Uri contentUri) {
        // 定义要查询的列
        String[] projection = {MediaStore.Images.Media.DATA};
        // 使用ContentResolver来查询内容提供者，获取包含指定列（文件路径）的Cursor
        Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null);
        if (cursor != null) {
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            String path = cursor.getString(column_index);
            cursor.close();
            return path;
        }
        return null;
    }

    // 创建输入框
    private EditText createEditText(String hint, int inputType) {
        EditText editText = new EditText(this);
        editText.setHint(hint);        // 设置提示文本
        editText.setInputType(inputType); // 设置输入类型

        // 如果提示中包含星号，则将星号部分设置为红色
        if (hint.startsWith("*")) {
            SpannableString spannableHint = new SpannableString(hint);

            // 设置第一个字符（星号）为红色
            spannableHint.setSpan(new ForegroundColorSpan(Color.RED), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

            // 设置整个Hint文本
            editText.setHint(spannableHint);
        } else {
            editText.setHint(hint);
        }

        return editText;
    }

    // 创建 Gson 实例
    private static Gson createGsonInstance() {
        return new GsonBuilder()
                .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (src, typeOfSrc, context) ->
                        new JsonPrimitive(src.toString())) // 序列化为 ISO-8601 格式的字符串
                .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, typeOfT, context) ->
                        LocalDateTime.parse(json.getAsString())) // 反序列化
                .create();
    }

    // 校验参数
    private Map<String, Object> checkAndProcessParams(String budgetStr, String startDateStr, String endDateStr) {
        // 转换和验证其他参数
        double budget;
        LocalDateTime startDate, endDate;
        try {
            budget = Double.parseDouble(budgetStr);
            startDate = LocalDateTime.parse(startDateStr); // 需要用户按ISO-8601格式输入
            endDate = LocalDateTime.parse(endDateStr);
        } catch (Exception e) {
            Toast.makeText(FileChooserActivity.this, "参数格式错误，请检查预算和日期", Toast.LENGTH_SHORT).show();
            return null;
        }

        Log.d(TAG, "参数为：" + budgetStr + " " + startDateStr + " " + endDateStr);
        Log.d(TAG, "参数没有异常");
        // 将结果存储到 Map 并返回
        Map<String, Object> result = new HashMap<>();
        result.put("budget", budget);
        result.put("startDate", startDate);
        result.put("endDate", endDate);
        return result;
    }

    public void handleResponse(Context context, String tag, Response<Result> response, Throwable t) {
        if (t != null) {
            // 处理网络错误
            Toast.makeText(context, "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
            Log.e(tag, "网络错误: " + t.getMessage());
            return;
        }

        if (response.isSuccessful() && response.body() != null) {
            Result result = response.body();
            if ("1".equals(result.getCode())) {
                // 处理成功
                Toast.makeText(context, "上传成功！！！", Toast.LENGTH_SHORT).show();
            } else {
                // 处理业务逻辑失败
                Log.e(tag, "上传失败，错误信息：" + result.getMessage());
                Toast.makeText(context, result.getMessage(), Toast.LENGTH_SHORT).show();
            }
        } else {
            // 处理 HTTP 错误
            try {
                String errorBody = response.errorBody() != null ? response.errorBody().string() : "null";
                Log.e(tag, "上传失败，HTTP状态码：" + response.code() + "，错误信息：" + errorBody);
            } catch (IOException e) {
                Log.e(tag, "上传失败，无法读取错误信息", e);
            }
            Toast.makeText(context, "上传失败，HTTP状态码：" + response.code(), Toast.LENGTH_SHORT).show();
        }
    }

    private Map<String, EditText> createInputFields() {
        Map<String, EditText> inputFields = new HashMap<>();

        inputFields.put("url", createEditText("*URL (例如：https://example.com)", InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI));
        inputFields.put("tags", createEditText("广告标签 (例如：Tag1,Tag2)", InputType.TYPE_CLASS_TEXT));
        inputFields.put("category", createEditText("广告类别 (例如：Retail)", InputType.TYPE_CLASS_TEXT));
        inputFields.put("budget", createEditText("*广告预算 (例如：5000.00)", InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL));
        inputFields.put("startDate", createEditText("*开始日期 (例如：2024-12-30T00:00:00)", InputType.TYPE_CLASS_TEXT));
        inputFields.put("endDate", createEditText("*结束日期 (例如：2025-01-05T23:59:59)", InputType.TYPE_CLASS_TEXT));
        inputFields.put("description", createEditText("广告描述", InputType.TYPE_CLASS_TEXT));
        inputFields.put("remark", createEditText("备注", InputType.TYPE_CLASS_TEXT));

        return inputFields;
    }

    public static String getMimeType(String filePath) {
        String extension = MimeTypeMap.getFileExtensionFromUrl(filePath);
        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }

    private UploadFileParamsDto createUploadParams(Map<String, EditText> inputFields) {
        UploadFileParamsDto uploadFileParams = new UploadFileParamsDto();

        // 提取并设置参数
        String tags = inputFields.get("tags").getText().toString().trim();
        String category = inputFields.get("category").getText().toString().trim();
        String budgetStr = inputFields.get("budget").getText().toString().trim().isEmpty() ? "3000.0" : "5000.0";
        String startDateStr = inputFields.get("startDate").getText().toString().trim().isEmpty() ? "2024-12-30T12:12:11" : "2024-12-30T12:12:12";
        String endDateStr = inputFields.get("endDate").getText().toString().trim().isEmpty() ? "2025-01-05T23:59:58" : "2025-01-05T23:59:59";
        String description = inputFields.get("description").getText().toString().trim();
        String remark = inputFields.get("remark").getText().toString().trim();

        // 设置非必填字段
        uploadFileParams.setTags(tags.isEmpty() ? null : tags);
        uploadFileParams.setCategory(category.isEmpty() ? null : category);
        uploadFileParams.setDescription(description.isEmpty() ? null : description);
        uploadFileParams.setRemark(remark.isEmpty() ? null : remark);

        // 验证并设置必填字段
        try {
            // 预算校验
            double budget = Double.parseDouble(budgetStr);
            if (budget <= 0) {
                throw new IllegalArgumentException("预算必须大于 0");
            }
            uploadFileParams.setBudget(budget);

            // 日期校验
            LocalDateTime startDate = LocalDateTime.parse(startDateStr);
            LocalDateTime endDate = LocalDateTime.parse(endDateStr);

            if (endDate.isBefore(startDate)) {
                throw new IllegalArgumentException("结束日期必须晚于开始日期");
            }

            uploadFileParams.setStartDate(startDate);
            uploadFileParams.setEndDate(endDate);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("预算格式不正确，应为数字类型");
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("日期格式不正确，请使用 ISO-8601 格式，例如：2024-12-30T12:12:12");
        }

        return uploadFileParams;
    }

}